package org.example.context.event;

import org.example.context.ApplicationEvent;
import org.example.context.ApplicationListener;
import org.example.exception.BeansException;
import org.example.factory.BeanFactory;
import org.example.factory.BeanFactoryAware;
import org.example.util.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @Author: luyg
 * @Date: 2024/09/12/23:03
 * @Description:
 */
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    @Override
    public void addApplicationListener(ApplicationListener<?> applicationListener) {
        this.applicationListeners.add((ApplicationListener<ApplicationEvent>) applicationListener);
    }

    @Override
    public void removeApplicationEvent(ApplicationListener<?> applicationListener) {
        this.applicationListeners.remove(applicationListener);
    }

    @Override
    public final void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }


    protected Collection<ApplicationListener> getApplicationLister(ApplicationEvent applicationEvent){
        List<ApplicationListener> applicationListenersList = new LinkedList<ApplicationListener>();
        for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
            if(supportsEvent(applicationListener,applicationEvent)) applicationListenersList.add(applicationListener);
        }
        return applicationListenersList;
    }

    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener,ApplicationEvent applicationEvent){
        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
        Class<?> aClass = ClassUtils.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = aClass.getGenericInterfaces()[0];
        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String typeName = actualTypeArgument.getTypeName();
        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(typeName);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name: " + typeName);
        }
        // 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同，或是否是其超类或超接口。
        // isAssignableFrom是用来判断子类和父类的关系的，或者接口的实现类和接口的关系的，默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true，证明B可以转换成为A,也就是A可以由B转换而来。
        return eventClassName.isAssignableFrom(applicationEvent.getClass());
    }

}
